/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_BF_AND_CAN.c
** 模块名称： 八方CAN和安乃达CAN兼容协议模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
**           V1.1     蒲磊      2023.03.13    1.针对N32L406和AT单片机，做了宏定义区分底层函数
**                                            2.修改了电量在没有获取到协议类型时，返回0的Bug。应返回-1
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include "App_Protocol_BF_AND_CAN.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/

/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/

/******************************************************************************
* 全局变量定义
******************************************************************************/
uint8_t gucProtocolType = NULL_PROTOCOL;        /*用于判断协议类型的变量*/
uint8_t gucErr = 0;
static uint32_t gulCommunicationCnt = 0;
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/


/******************************************************************************
** 功  能：CAN协议初始化函数
** 参  数：无
** 返回值：无
** 备  注：用于初始化CAN协议模块的相关变量，同时创建收发队列。
**        该函数需要在BF_CAN_CanToBF函数调用之前初始化
******************************************************************************/
void vPROTOCOL_Init(void)
{
    muilt_cyc_fifo_error_code_t    lxState;
    MCF_ApplyFifo(gxCAN_RxQueue_Len,gxCAN_RxQueue,&lxState);     /*初始化接收队列*/
    MCF_ApplyFifo(gxCAN_TxQueue_Len,gxCAN_TxQueue,&lxState);     /*初始化发送队列*/

    vPROTOCOL_ANANDA_Init();
}

/******************************************************************************
** 功  能：CAN轮询主函数
** 参  数：无
** 返回值：无
** 备  注：该函数判断接收缓冲区是否有数据，如有，则取出并处理，同时判断发送缓冲区是否有
**        数据，如果有，取出并发送。
**        该函数需要循环调用，调用周期应小于最小接收周期和最小发送周期
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    switch(gucProtocolType)
    {
    case NULL_PROTOCOL:
    {
        /*10S之内，通信超时变量未复位，报30错误*/
        gulCommunicationCnt ++;
        if(gulCommunicationCnt > (12000 / CAN_LOOP_CYCLE))
        {
            gucErr = 0x30;
        }
        else
        {
            if(gucErr == 0x30)
            {
                gucErr = 0;
            }
        }
        break;
    }
    case BF_PROTOCOL:
    {
        vPROTOCOL_BF_Loop();            /*八方协议，调用八方轮询函数*/
        break;
    }
    case AND_PROTOCOL:
    {
        vPROTOCOL_ANANDA_Loop();        /*安乃达协议，调用安乃达轮询函数*/
        break;
    }
    }
}

#if defined N32L40X     /*该宏定义在工程选项菜单中被定义*/
/******************************************************************************
** 功  能：将接收到的Can帧解析为对应的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为八方或者安乃达的CAN数据格式，并且放入接收队列
******************************************************************************/
void vPROTOCOL_CanMsgToProtocolMsg(CanRxMessage *pCanMessage)
{
    switch(gucProtocolType)
    {
    case NULL_PROTOCOL:
    {
        /*此时还没有判断出CAN协议类型。根据两个协议的特征帧来判断。八方协议判断0x02F83201帧，安乃达判断0x18FE02EF帧*/
        if(pCanMessage->ExtId == 0x18FE02EF)
        {
            gucProtocolType = AND_PROTOCOL;
        }
        else if(pCanMessage->ExtId == 0x02F83201)
        {
            vbsp_CAN_Set_BF_Filter();       /*确定是八方协议时，重新设置八方的CAN过滤器。屏蔽掉传感器帧*/
            gucProtocolType = BF_PROTOCOL;
        }
        break;
    }
    case BF_PROTOCOL:
    {
        vPROTOCOL_CanMsgToBFMsg(pCanMessage);            /*八方协议，调用八方轮询函数*/
        break;
    }
    case AND_PROTOCOL:
    {
        vPROTOCOL_CanMsgToANANDAMsg(pCanMessage);        /*安乃达协议，调用安乃达轮询函数*/
        break;
    }
    }
}
#else
/******************************************************************************
** 功  能：将接收到的Can帧解析为对应的Can数据结构
** 参  数：pCanMessage-接收到的Can数据结构体指针
** 返回值：无
** 备  注：该函数是整个Can协议模块的入口函数。当CAN总线接收一帧Can数据后，调用该函数，
**        将Can消息帧转换为八方或者安乃达的CAN数据格式，并且放入接收队列
******************************************************************************/
void vPROTOCOL_CanMsgToProtocolMsg(can_rx_message_type *pCanMessage)
{
    switch(gucProtocolType)
    {
    case NULL_PROTOCOL:
    {
        /*此时还没有判断出CAN协议类型。根据两个协议的特征帧来判断。八方协议判断0x02F83201帧，安乃达判断0x18FE02EF帧*/
        if(pCanMessage->extended_id == 0x18FE02EF)
        {
            gucProtocolType = AND_PROTOCOL;
        }
        else if(pCanMessage->extended_id == 0x02F83201)
        {
            vbsp_CAN_Set_BF_Filter();       /*确定是八方协议时，重新设置八方的CAN过滤器。屏蔽掉传感器帧*/
            gucProtocolType = BF_PROTOCOL;
        }
        break;
    }
    case BF_PROTOCOL:
    {
        vPROTOCOL_CanMsgToBFMsg(pCanMessage);            /*八方协议，调用八方轮询函数*/
        break;
    }
    case AND_PROTOCOL:
    {
        vPROTOCOL_CanMsgToANANDAMsg(pCanMessage);        /*安乃达协议，调用安乃达轮询函数*/
        break;
    }
    }
}
#endif
/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    vPROTOCOL_Set_Value_When_PowerOn_BF();
    vPROTOCOL_Set_Value_When_PowerOn_AND();
}


/******************************************************************************
** 功  能：设置按键状态
** 参  数：KeyValue-按键键值
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Button(uint8_t KeyValue)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:
    {
        vPROTOCOL_Set_Button_BF(KeyValue);
        break;
    }
    case AND_PROTOCOL:
    {
        vPROTOCOL_Set_Button_AND(KeyValue);
        break;
    }
    }
}


/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        vBF_CAN_Set_Lamp(State);
        break;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        vANANDA_Set_Lamp(State);
        break;
    }
    }
}

/******************************************************************************
** 功  能：设置档位范围
** 参  数：Pas_Range
** 返回值：无
** 备  注：安乃达控制器，默认支持5个挡位，当选择3档位时，发送1、3、5档
**         特殊7档和9档的，需要更改控制器程序，暂不考虑
******************************************************************************/
void vPROTOCOL_Set_Pas_Range(int8_t Pas_Range)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        vBF_CAN_Set_MaxPas(Pas_Range);
        break;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        vANANDA_Set_Pas_Range(Pas_Range);
        break;
    }
    }
}

/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：本函数在仪表为主机的模式下可用，在TUV模式下，仪表发送的档位是转发控制器的数据
**         不要调用该函数
**         安乃达控制器，默认支持5个挡位，当选择3档位时，发送1、3、5档
**         特殊7档和9档的，需要更改控制器程序，暂不考虑
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        vBF_CAN_Set_Pas(Pas);
        break;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        vANANDA_Set_Pas(Pas);
        break;
    }
    }
}

/******************************************************************************
** 功  能：设置清Trip
** 参  数：State-是否清Trip，0-不清，1-清Trip
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_ClearTrip(uint8_t State)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        vBF_CAN_Set_ClearTrip();
        break;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        vANANDA_Set_ClearTrip(State);
        break;
    }
    }
}

/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return usBF_CAN_Get_MCU_Speed() / 10;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return usANANDA_Get_Speed();
    }
    default:
    {
        return 0;
    }
    }
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十六进制的错误代码
** 备  注：包括30错误代码（通信超时）
******************************************************************************/
uint8_t ucPROTOCOL_Get_Errcode(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return ucBF_CAN_Get_ErrCode();
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return ucANANDA_Get_Errcode();
    }
    case NULL_PROTOCOL:
    {
        return gucErr;
    }
    default:
    {
        return 0;
    }
    }

}

/******************************************************************************
** 功  能：获取功率值
** 参  数：无
** 返回值：电机功率值，单位W
** 备  注：八方协议是根据电压和电流计算，安乃达协议直接读取功率
******************************************************************************/
uint16_t usPROTOCOL_Get_Power(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return usBF_CAN_Get_MCU_Current() * usBF_CAN_Get_MCU_Voltage() / 10000;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return usANANDA_Get_Motor_Power() / 10;
    }
    default:
    {
        return 0;
    }
    }

}

/******************************************************************************
** 功  能：获取电量
** 参  数：无
** 返回值：电量，没有电量数据，返回-1
** 备  注：八方协议是直接读控制器发送的电量，安乃达读BMS的电量，没有，返回-1
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return ucBF_CAN_Get_MCU_RemainCapacity();
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return cANANDA_Get_BMS_SOC();   /*不支持BMS时，会返回-1*/
    }
    default:
    {
        return -1;
    }
    }

}

/******************************************************************************
** 功  能：获取电压值
** 参  数：无
** 返回值：电压值，精度0.1V，没有电压数据，返回0
** 备  注：八方协议是直接读控制器发送的，安乃达读BMS的，没有，返回0
******************************************************************************/
uint16_t usPROTOCOL_Get_Voltage(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return usBF_CAN_Get_MCU_Voltage() / 10;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return usANANDA_Get_BMS_Voltage();   /*不支持BMS时，会返回0*/
    }
    default:
    {
        return 0;
    }
    }

}

/******************************************************************************
** 功  能：获取助推状态
** 参  数：无
** 返回值：0-未助推，1-进入助推
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_WalkState(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return ucBF_CAN_Get_MCU_PushState();
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return ucANANDA_Get_Push_Status() == 2 ? 1:0;   /*安乃达助推状态，0-未助推，1-准备状态，2-助推中，实际返回，当助推工作时返回1，否则返回0*/
    }
    default:
    {
        return 0;
    }
    }

}

/******************************************************************************
** 功  能：获取关机指令
** 参  数：无
** 返回值：0-不关机，1-关机
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_PowerOff(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return ucBF_CAN_Get_MCU_PowerOff() == 0 ? 1:0;  /*八方CAN，0表示关机，1表示不关机*/
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return ucANANDA_Get_PowerOff() == 0 ? 0:1;
    }
    default:
    {
        return 0;
    }
    }

}

/******************************************************************************
** 功  能：获取显示的轮径索引值
** 参  数：无
** 返回值：轮径英寸值×10，比如27寸，返回270，700C返回275
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Wheel(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return usBF_CAN_Get_MCU_WheelSize();
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return usANANDA_Get_Wheel();
    }
    default:
    {
        return 0;
    }
    }
}


/******************************************************************************
** 功  能：获取限速值
** 参  数：无
** 返回值：限速值，0.1km/h
** 备  注：
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed_Limit(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        return usBF_CAN_Get_MCU_SpeedLimit() / 10;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        return usANANDA_Get_Speed_Limit();
    }
    default:
    {
        return 0;
    }
    }
}

/******************************************************************************
** 功  能：复位通信超时
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    switch(gucProtocolType)
    {
    case BF_PROTOCOL:   /*八方协议*/
    {
        vBF_ResetCommunicationOverTime();
        break;
    }
    case AND_PROTOCOL:  /*安乃达协议*/
    {
        vANANDA_ResetCommunicationOverTime();
        break;
    }
    case NULL_PROTOCOL:
    {
        gulCommunicationCnt = 0;
        break;
    }
    }
}

/******************************************************************************
** 功  能：获取当前协议类型
** 参  数：无
** 返回值：0-未获取到。1-八方CAN，2-安乃达CAN
** 备  注：
******************************************************************************/
uint8_t ucPROTOCOL_Get_Type(void)
{
    return gucProtocolType;
}
